/*
 * NyuString.cpp
 *
 *  Created on: 2010/05/23
 *      Author: mitsu
 */

#include <cstdlib>
#include "NyuString.hpp"
#include "NyuStrPool.hpp"

NyuString::NyuString(unsigned int hash) :
        hash_(hash) {
}

NyuString* NyuString::to_str(NyuContext* c) {
    return this;
}

NyuValue NyuString::opEq(NyuValue other, NyuContext* c, bool is_tail) {
    if (!NYU_VALUE_IS_OBJECT(other))
        return false;

    NyuObject* obj = NYU_VALUE_UNTAG_OBJECT(other);
    if (NYU_OBJECT_TO_VALUE(this) == other)
        return true;

    return obj->revEqStr(this->strval(), c, is_tail);
}

NyuValue NyuString::revEqStr(const char* str, NyuContext* c, bool is_tail) {
    return NYU_INT_TO_VALUE(::strcmp(str, strval()) == 0);
}

unsigned int NyuString::hash() const {
    return hash_;
}

unsigned int NyuString::calcHash(const char* str) {
    unsigned int h = 0;

    for (const unsigned char* p = (const unsigned char*)str; *p; ++p) {
        h = 31 * h + *p;
    }

    return h;
}

NyuValue NyuString::fromCharCodeFunc(NyuContext* c) {
    NyuValue val = c->current_argv(1);
    NyuInt ch = 0;
    switch (NYU_VALUE_TAG(val)) {
    case NYU_VALUE_TAG_INT:
        ch = NYU_VALUE_TO_INT(val);
        break;

    case NYU_VALUE_TAG_NATIVE:
        break;

    case NYU_VALUE_TAG_OBJECT:
        ch = NYU_VALUE_UNTAG_OBJECT(val)->to_int(c);
        break;

    case NYU_VALUE_TAG_BLOCK:
        break;
    }

    char* s = static_cast<char*>(::malloc(2));
    s[0] = static_cast<char>(ch);
    s[1] = '\0';
    return NYU_OBJECT_TO_VALUE(new NyuImmutableString(s));
}

///////////////////////////////////////////////////////////////////////////////

NyuImmutableString::NyuImmutableString(char* strval) :
        NyuString(calcHash(strval)), strval_(strval) {
}

NyuImmutableString::NyuImmutableString(char* strval, unsigned int hash) :
        NyuString(hash), strval_(strval) {
}

NyuImmutableString::~NyuImmutableString() {
    free(strval_);
}

const char* NyuImmutableString::strval() const {
    return strval_;
}

void NyuImmutableString::dispose() {
    this->~NyuImmutableString();
    ::operator delete(this);
}

///////////////////////////////////////////////////////////////////////////////

NyuStaticString::NyuStaticString(const char* strval) :
        NyuString(calcHash(strval)), strval_(strval) {
    NyuStrPool::addStatic(this);
}

const char* NyuStaticString::strval() const {
    return strval_;
}

void NyuStaticString::dispose() {
    // Nothing to do
}

NyuStaticString NyuStaticString::PROTO("__proto__");
NyuStaticString NyuStaticString::OBJECT("Object");
NyuStaticString NyuStaticString::STRING("String");
NyuStaticString NyuStaticString::FROM_CHAR_CODE("fromCharCode");
NyuStaticString NyuStaticString::RANGE("Range");
NyuStaticString NyuStaticString::START("start");
NyuStaticString NyuStaticString::END("end");
NyuStaticString NyuStaticString::STEP("step");
NyuStaticString NyuStaticString::BORDER("border");
NyuStaticString NyuStaticString::EACH("each");
NyuStaticString NyuStaticString::ARRAY("Array");
NyuStaticString NyuStaticString::LENGTH("length");
NyuStaticString NyuStaticString::PUSH("push");
NyuStaticString NyuStaticString::POP("pop");

NyuStaticString NyuStaticString::INT("__int__");

NyuStaticString NyuStaticString::NOT("__not__");
NyuStaticString NyuStaticString::INVERT("__invert__");
NyuStaticString NyuStaticString::POS("__pos__");
NyuStaticString NyuStaticString::NEG("__neg__");
NyuStaticString NyuStaticString::INCR("__incr__");
NyuStaticString NyuStaticString::DECR("__decr__");
NyuStaticString NyuStaticString::POST_INCR("__postincr__");
NyuStaticString NyuStaticString::POST_DECR("__postdecr__");
NyuStaticString NyuStaticString::ADD("__add__");
NyuStaticString NyuStaticString::SUB("__sub__");
NyuStaticString NyuStaticString::MUL("__mul__");
NyuStaticString NyuStaticString::DIV("__div__");
NyuStaticString NyuStaticString::MOD("__mod__");
NyuStaticString NyuStaticString::CALL("__call__");
